#include <modules\system\win32\win32_system_interface.h>

namespace DelGE
{
	namespace Modules
	{
		namespace System
		{
			LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
			{
				Win32SystemWindow* window = reinterpret_cast<Win32SystemWindow*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));

				if (window)
				{
					window->ProcessEvent(msg, wParam, lParam);
				}

				if (msg == WM_CLOSE)
					return 0;

				return DefWindowProc(hwnd, msg, wParam, lParam);
			}

			Win32SystemInterface::Win32SystemInterface()
			{
				this->sName = "Win32 System Interface";

				CreateWindowClass();
			}

			Win32SystemInterface::~Win32SystemInterface()
			{
			}

			void Win32SystemInterface::CreateWindowClass()
			{
				WNDCLASSEX windowClass;
				HINSTANCE hInstance;

				// get the current module handle
				hInstance					= GetModuleHandle(NULL);

				windowClass.cbSize			= sizeof(WNDCLASSEX);
				windowClass.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

				windowClass.lpfnWndProc		= WndProc;
				windowClass.cbClsExtra		= 0;
				windowClass.cbWndExtra		= 0;
				windowClass.hInstance		= hInstance;
				windowClass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
				windowClass.hCursor			= LoadCursor(NULL, IDC_ARROW);
				windowClass.hbrBackground	= (HBRUSH)(COLOR_WINDOW + 1);
				windowClass.lpszMenuName	= NULL;
				windowClass.lpszClassName	= "windowClass";
				windowClass.hIconSm			= LoadIcon(NULL, IDI_APPLICATION);

				RegisterClassEx(&windowClass);
			}

			void Win32SystemInterface::Update()
			{
				MSG rMessage;

				while (PeekMessage(&rMessage, NULL, 0, 0, PM_REMOVE))
				{
					TranslateMessage(&rMessage);
					DispatchMessage(&rMessage);
				}
			}

			vector<SystemVideoMode> Win32SystemInterface::GetSupportedVideoModes()
			{
				vector<SystemVideoMode> lVideoModes;
				DEVMODE deviceMode;
				deviceMode.dmSize = sizeof(deviceMode);

				for (int i = 0; EnumDisplaySettings(NULL, i, &deviceMode); ++i)
				{
					SystemVideoMode systemVideoMode(deviceMode.dmPelsWidth, deviceMode.dmPelsHeight, deviceMode.dmBitsPerPel);

					if (find(lVideoModes.begin(), lVideoModes.end(), systemVideoMode) == lVideoModes.end())
						lVideoModes.push_back(systemVideoMode);
				}

				sort(lVideoModes.begin(), lVideoModes.end());

				return lVideoModes;
			}

			SystemVideoMode Win32SystemInterface::GetCurrentVideoMode()
			{
				DEVMODE deviceMode;
				deviceMode.dmSize = sizeof(deviceMode);

				if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &deviceMode))
					return SystemVideoMode(deviceMode.dmPelsWidth, deviceMode.dmPelsHeight, deviceMode.dmBitsPerPel);

				return SystemVideoMode(0, 0, 0);
			}

			void Win32SystemInterface::ChangeVideoMode(const SystemVideoMode &systemVideoMode)
			{
				if (!this->IsVideoModeSupported(systemVideoMode))
					return; // why are you trying to break it!

				DEVMODE deviceMode;

				deviceMode.dmSize		= sizeof(DEVMODE);
				deviceMode.dmPelsWidth	= systemVideoMode.GetWidth();
				deviceMode.dmPelsHeight	= systemVideoMode.GetHeight();
				deviceMode.dmBitsPerPel	= systemVideoMode.GetBitsPerPixel();
				deviceMode.dmFields		= DM_PELSWIDTH |
										  DM_PELSHEIGHT |
										  DM_BITSPERPEL;

				ChangeDisplaySettings(&deviceMode, CDS_FULLSCREEN);
			}

			void Win32SystemInterface::RestoreVideoMode()
			{
				ChangeDisplaySettings(NULL, 0);
			}

			void Win32SystemInterface::HideMouse()
			{
				ShowCursor(FALSE);
			}

			void Win32SystemInterface::ShowMouse()
			{
				ShowCursor(TRUE);
			}
		}
	}
}